package com.tanjun.web.annotation.aspect;

import cn.hutool.core.util.StrUtil;
import com.tanjun.common.enums.err.LoginErrCode;
import com.tanjun.common.exception.BizException;
import com.tanjun.web.annotation.HasRole;
import com.tanjun.web.service.LoginUserUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

@Component
@Aspect
@Slf4j
public class HasRoleAspect {
    /**
     * 登录验证
     *
     * @param joinPoint
     * @return
     */
    @Around("@within(com.tanjun.web.annotation.HasRole)||@annotation(com.tanjun.web.annotation.HasRole)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 1. 检查方法上是否有注解
        HasRole methodHasRole = method.getAnnotation(HasRole.class);
        if (methodHasRole != null) {
            log.info("method has hasRole, method name:{},hasRole:{}", method.getName(), methodHasRole);
            checkHasRole(methodHasRole);
        }

        HasRole classHasRole = joinPoint.getTarget().getClass().getAnnotation(HasRole.class);
        if (classHasRole != null) { // 避免重复处理
            log.info("class has hasRole,class name: {}", signature.getClass().getName());
            checkHasRole(classHasRole);
        }
        // 执行目标方法
        return joinPoint.proceed();

    }

    private void checkHasRole(HasRole hasRole) {
        List<String> roles = LoginUserUtil.getUserRoles();
        if (StrUtil.isNotEmpty(hasRole.value()) && !roles.contains(hasRole.value())) {
            throw new BizException(LoginErrCode.NOT_ROLE);
        }
        if (hasRole.values() != null && hasRole.values().length > 0) {
            boolean hasRoleFlag = roles.stream().anyMatch(role -> Arrays.asList(hasRole.values()).contains(role));
            if (!hasRoleFlag) {
                throw new BizException(LoginErrCode.NOT_ROLE);
            }
        }
    }
}
